#include <QMutexLocker>
#include <QHBoxLayout>
#include <QMouseEvent>
#include "cameragraphicsview.h"

#define ZOOMMAX 50   //最大放大倍数
#define ZOOMMIN 0.02 //最小缩小倍数

CameraGraphicsView::CameraGraphicsView(QWidget *parent)
    : QGraphicsView(parent)
    , m_pImageItem(Q_NULLPTR)
    , m_pInfoLabel(Q_NULLPTR)
{
    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    this->setRenderHint(QPainter::Antialiasing);
    this->setTransformationAnchor(QGraphicsView::AnchorViewCenter);
    this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
    this->setSceneRect(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
    setBackground();
    centerOn(0, 0);

    connect(this,&CameraGraphicsView::ShowNewImage,this,&CameraGraphicsView::DoShowNewImage);

    InitWidget();
}

CameraGraphicsView::~CameraGraphicsView(){
    delete m_pInfoLabel;
    delete m_pInfoWidget;
    delete m_pResultImagetItem;
    delete m_pImageItem;
    delete m_pScene;
}

bool CameraGraphicsView::InitWidget()
{
    //创建变量对象
    m_pScene = new QGraphicsScene(this);
    m_pImageItem = new CameraImageItem(this);

    m_pImageItem->setAcceptHoverEvents(true);
    m_pImageItem->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
    this->setScene(m_pScene);
    m_pScene->addItem(m_pImageItem);


    //信息框
    m_pInfoLabel = new QLabel(this);
    //在视觉窗口下方显示鼠标坐标以及图像的灰度值
    m_pInfoLabel->setStyleSheet("color:rgb(200,255,200); "
                                   "background-color:rgba(50,50,50,160); "
                                   "font: Times New Roman;"
                                   "font-size: 15px;");

    //m_pInfoLabel->setText("Camera");

    //显示区域窗口
    m_pInfoWidget = new QWidget(this);
    m_pInfoWidget->setFixedHeight(25);
    m_pInfoWidget->setGeometry(10, this->height() - 25, this->width(), 25);
    m_pInfoWidget->setStyleSheet("background-color:rgba(0,0,0,0);");

    QHBoxLayout *pInfoLayout = new QHBoxLayout();
    pInfoLayout->setSpacing(0);
    pInfoLayout->setContentsMargins(0, 0, 0, 0);
    pInfoLayout->addWidget(m_pInfoLabel);
    m_pInfoWidget->setLayout(pInfoLayout);
    //
    m_pResultImagetItem = new ResultImageItem(this);
    m_pScene->addItem(m_pResultImagetItem);
    m_pResultImagetItem->setScale(9.1);

    return true;
}

void CameraGraphicsView::SetImageResult(int nRet){
    m_pResultImagetItem->setVisible(true);
    m_pResultImagetItem->SetImageResult(nRet);
    m_pResultImagetItem->update();

    fitFrame();
    onCenter();
    show();
}

//设置视觉窗口的图像
void CameraGraphicsView::SetImage(const QImage &image){
    m_qImage = image.copy();

    m_Image = QPixmap::fromImage(m_qImage);
    m_pImageItem->w = m_Image.width();
    m_pImageItem->h = m_Image.height();
    m_pImageItem->setPixmap(m_Image);

    fitFrame();
    onCenter();
    show();
}

void CameraGraphicsView::ClearImage(){
    m_Image = QPixmap();
    m_pImageItem->w = m_Image.width();
    m_pImageItem->h = m_Image.height();
    m_pImageItem->setPixmap(m_Image);
    m_pImageItem->setPixmap(m_Image);
}

void CameraGraphicsView::SetImage(GX_FRAME_CALLBACK_PARAM* pFrame){
    int nWidth = pFrame->nWidth;
    int nHeight = pFrame->nHeight;
    char* pOutBuffer = (char*) malloc(nWidth * nHeight * 3 * sizeof(char));

    DxRaw8toRGB24((void *)pFrame->pImgBuf,
                  pOutBuffer,
                  nWidth,
                  nHeight,
                  DX_BAYER_CONVERT_TYPE::RAW2RGB_ADAPTIVE,
                  DX_PIXEL_COLOR_FILTER::BAYERRG,
                  true);


    // 加载BMP图像
    QImage image(nWidth,nHeight,QImage::Format_BGR888);
    memcpy(image.bits(),pOutBuffer,nWidth * nHeight * 3);

    m_qImage = image.copy();

    emit ShowNewImage();

    free( pOutBuffer);
}

void CameraGraphicsView::DoShowNewImage(){
    SetImage(m_qImage);
}

//绘制函数，用于视觉窗口背景绘制
void CameraGraphicsView::paintEvent(QPaintEvent *event)
{
    QPainter paint(this->viewport());
    //绘制背景
    paint.drawTiledPixmap(QRect(QPoint(0, 0), QPoint(this->width(), this->height())), m_tilePixmap);
    QGraphicsView::paintEvent(event);
}

//当窗口尺寸发生变化时，实时更新视觉窗口位置
void CameraGraphicsView::resizeEvent(QResizeEvent *event)
{
    fitFrame();
    onCenter();

    m_pInfoWidget->setGeometry(20, 20, this->width()/8, 45);

    QGraphicsView::resizeEvent(event);
}

//视图居中
void CameraGraphicsView::onCenter()
{
    //调用QGraphicsView自带的方法centerOn，使视觉窗口的中心位于图像元素的中心点
    //并设置m_pImageItem的坐标，使其也位于中心点
    this->centerOn(0, 0);
    m_pImageItem->setPos(-m_pImageItem->pixmap().width() / 2, -m_pImageItem->pixmap().height() / 2);
    m_pResultImagetItem->setPos(-m_pImageItem->pixmap().width() / 2, -m_pImageItem->pixmap().height() / 2);
}

void CameraGraphicsView::onZoom(float scaleFactor)
{
    //记录下当前相对于图像原图的缩放比例，可以记录下当前图像真实放大缩小了多少倍
    //可以借此来限制图像的最大或最小缩放比例
    m_dZoomValue *= scaleFactor;
    //调用视图类QGraphicsView自带的scale缩放方法，来对视图进行缩放，实现放大缩小的功能
    //缩放的同时，视图里的所有元素也会进行缩放，也就达到了视觉窗口放大缩小的效果
    this->scale(scaleFactor, scaleFactor);
}

//图片自适应方法，根据图像原始尺寸和当前视觉窗口的大小计算出应缩放的尺寸，再根据已经缩放的比例计算还差的缩放比例，
//补齐应缩放的比例，使得图像和视觉窗口大小相适配
void CameraGraphicsView::fitFrame()
{
    if (this->width() < 1 || m_Image.width() < 1)
        return;

    //计算缩放比例
    double winWidth = this->width();
    double winHeight = this->height();
    double ScaleWidth = (m_Image.width() + 1) / winWidth;
    double ScaleHeight = (m_Image.height() + 1) / winHeight;
    double s_temp = ScaleWidth >= ScaleHeight ? 1 / ScaleWidth : 1 / ScaleHeight;
    double scale = s_temp / m_dZoomValue;
    if ((scale >= ZOOMMAX) || (scale <= ZOOMMIN)) //最大放大到原始图像的50倍
    {
        return;
    }

    onZoom(scale);
    m_dZoomValue = s_temp;
}

//设置视觉窗口背景为棋盘格样式
void CameraGraphicsView::setBackground(bool enabled, bool invertColor)
{
    if (enabled) {
        m_tilePixmap.fill(invertColor ? QColor(220, 220, 220) : QColor(35, 35, 35));
        QPainter tilePainter(&m_tilePixmap);
        constexpr QColor color(50, 50, 50, 255);
        constexpr QColor invertedColor(210, 210, 210, 255);
        tilePainter.fillRect(0, 0, 18, 18, invertColor ? invertedColor : color);
        tilePainter.fillRect(18, 18, 18, 18, invertColor ? invertedColor : color);
        tilePainter.end();

        //当取消注释时，视觉窗口背景格会跟随图像一起缩放
        //setBackgroundBrush(m_tilePixmap);
    } else {
        //setBackgroundBrush(Qt::transparent);
    }
}

//在视觉窗口上双击鼠标左键，显示该图像的放大内容，包括缺陷
void CameraGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
{
    event->ignore();
}
